// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// d [author] rhyme_lph
// g [email]  rhymelph@gmail.com
// e [github] https://github.com/rhymelph

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/entities/product_entity.dart';
import 'package:finance_app/src/entities/services_entity.dart';
import 'package:finance_app/src/http_service/http_product_service.dart';
import 'package:finance_app/src/http_service/http_services_service.dart';
import 'package:finance_app/src/mixin/search_data_map_mixin.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:flutter/material.dart';

class BatchProductsAndServicesProvider extends BaseProvider
    with SearchDataMapMixin {
  List<ProductEntity> allProductData = [];
  List<ServicesEntity> allServiceData = [];

  List<ProductEntity> currentSelectProduct = [];
  List<ServicesEntity> currentSelectService = [];
  bool isService;

  bool isLoadFinish = false;

  String type;

  String currentSelectStatus;

  @override
  Future get dataFuture => null;

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  List<ServicesEntity> filterService(List<ServicesEntity> data) {
    if (type == 'Deactivate') {
      return data.where((element) => element.isActivated == 1).toList();
    } else if (type == 'Activate') {
      return data.where((element) => element.isActivated == 0).toList();
    } else if (type == 'Delete') {
      if (currentSelectStatus == 'Active') {
        return data.where((element) => element.isActivated == 1).toList();
      } else if (currentSelectStatus == 'Inactive') {
        return data.where((element) => element.isActivated == 0).toList();
      }
    }
    return data;
  }

  List<ProductEntity> filterProduct(List<ProductEntity> data) {
    if (type == 'Deactivate') {
      return data.where((element) => element.isActivated == 1).toList();
    } else if (type == 'Activate') {
      return data.where((element) => element.isActivated == 0).toList();
    } else if (type == 'Delete') {
      if (currentSelectStatus == 'Active') {
        return data.where((element) => element.isActivated == 1).toList();
      } else if (currentSelectStatus == 'Inactive') {
        return data.where((element) => element.isActivated == 0).toList();
      }
    }
    return data;
  }

  void _loadData() async {
    if (isService) {
      await post(HttpServicesService.serviceList(),
          autoHandler: AutoHandler.Toast, onSuccess: (result) {
        allServiceData =
            filterService(getEntityFromResult<List<ServicesEntity>>(result));
        allServiceData.sort(
            (a, b) => a.name.toUpperCase().compareTo(b.name.toUpperCase()));
        for (final item in allServiceData) {
          searchDataClassification(item);
        }
      }, onFinally: () {
        isLoadFinish = true;
        update();
      });
    } else {
      await post(HttpProductService.productList(),
          autoHandler: AutoHandler.Toast, onSuccess: (result) {
        allProductData =
            filterProduct(getEntityFromResult<List<ProductEntity>>(result));
        allProductData.sort(
            (a, b) => a.name.toUpperCase().compareTo(b.name.toUpperCase()));
        for (final item in allProductData) {
          searchDataClassification(item);
        }
      }, onFinally: () {
        isLoadFinish = true;
        update();
      });
    }
  }

  void searchDataClassification(dynamic item) {
    if (item.name.length > 0) {
      String firstName = (item.name[0] as String).toUpperCase();
      if (searchData.containsKey(firstName)) {
        searchData[firstName].add(item);
      } else {
        searchData[firstName] = [item];
      }
    } else {
      if (searchData['*'] != null) {
        searchData["*"].add(item);
      } else {
        searchData['*'] = [item];
      }
    }
  }

  void onSelectProduct(ProductEntity data) {
    if (currentSelectProduct.contains(data)) {
      currentSelectProduct.remove(data);
    } else {
      currentSelectProduct.add(data);
    }
    update();
  }

  void onSelectService(ServicesEntity data) {
    if (currentSelectService.contains(data)) {
      currentSelectService.remove(data);
    } else {
      currentSelectService.add(data);
    }
    update();
  }

  void onCancel() {
    obtainContext?.call((context) {
      Navigator.of(context).pop();
    });
  }

  Future<void> operationService(
      BuildContext context,
      Future future,
      bool remove(ServicesEntity entity),
      Future<bool> showTip(),
      Future<void> showSuccess()) async {
    bool isSuccess = await showTip();
    if (isSuccess == true) {
      isSuccess = false;
      await post(future, autoHandler: AutoHandler.Toast, onSuccess: (result) {
        isSuccess = true;
      }, loadingTip: S.current.loading);
      if (isSuccess == true) {
        allServiceData.removeWhere(remove);
        currentSelectProduct.clear();
        searchData.clear();
        for (final item in allServiceData) {
          searchDataClassification(item);
        }
        await showSuccess();
        update();
      }
    }
  }

  Future<void> operationProduct(
      BuildContext context,
      Future future,
      bool remove(ProductEntity entity),
      Future<bool> showTip(),
      Future<void> showSuccess()) async {
    bool isSuccess = await showTip();
    if (isSuccess == true) {
      isSuccess = false;
      await post(future, autoHandler: AutoHandler.Toast, onSuccess: (result) {
        isSuccess = true;
      }, loadingTip: S.current.loading);
      if (isSuccess == true) {
        allProductData.removeWhere(remove);
        currentSelectProduct.clear();
        searchData.clear();
        for (final item in allProductData) {
          searchDataClassification(item);
        }
        await showSuccess();
        update();
      }
    }
  }

  void onOperation(bool isService, String type) {
    unFocus();
    List<int> ids;
    if (isService) {
      ids = currentSelectService.map((e) => e.id).toList();
    } else {
      ids = currentSelectProduct.map((e) => e.id).toList();
    }
    if (ids.length == 0) {
      showToast(S.current.please_select_item);
      return;
    }

    obtainContext?.call((context) async {
      switch (type) {
        case 'Deactivate':
          if (isService) {
            await operationService(
              context,
              HttpServicesService.serviceBatchDeactivate(ids),
              (element) => ids.contains(element.id),
              () async => await showServiceDeactivateInfoBottomSheet(context),
              () async =>
                  await showServiceDeActivatedSuccessBottomSheet(context),
            );
          } else {
            await operationProduct(
              context,
              HttpProductService.productBatchDeactivate(ids),
              (element) => ids.contains(element.id),
              () async => await showProductDeactivateInfoBottomSheet(context),
              () async =>
                  await showProductDeActivatedSuccessBottomSheet(context),
            );
          }
          obtainContext?.call((context) {
            Navigator.of(context).pop(true);
          });
          break;
        case 'Delete':
          if (isService) {
            await operationService(
              context,
              HttpServicesService.serviceBatchDelete(ids),
              (element) => ids.contains(element.id),
              () async => await showServiceDeleteInfoBottomSheet(context),
              () async => await showServiceDeleteSuccessBottomSheet(context),
            );
          } else {
            await operationProduct(
              context,
              HttpProductService.productBatchDelete(ids),
              (element) => ids.contains(element.id),
              () async => await showProductDeleteInfoBottomSheet(context),
              () async => await showProductDeleteSuccessBottomSheet(context),
            );
          }
          obtainContext?.call((context) {
            Navigator.of(context).pop(true);
          });
          break;
        case 'Activate':
          if (isService) {
            List<int> ids = currentSelectService.map((e) => e.id).toList();
            await operationService(
              context,
              HttpServicesService.serviceBatchActivate(ids),
              (element) => ids.contains(element.id),
              () async => await Future.value(true),
              () async => await showServiceActivatedSuccessBottomSheet(context),
            );
          } else {
            await operationProduct(
              context,
              HttpProductService.productBatchActivate(ids),
              (element) => ids.contains(element.id),
              () async => Future.value(true),
              () async => await showProductActivatedSuccessBottomSheet(context),
            );
          }
          obtainContext?.call((context) {
            Navigator.of(context).pop(true);
          });
          break;
      }
    });
  }
}
